/*
 * Copyright (c) 2016 Zodiac Inflight Innovation
 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
 *
 * Based on code found in Linux kernel and U-Boot.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef __lpuart32_H__
#define __lpuart32_H__


/* 32-bit register definition */
#define LPUART32_UARTBAUD		0x00
#define LPUART32_UARTSTAT		0x04
#define LPUART32_UARTCTRL		0x08
#define LPUART32_UARTDATA		0x0C
#define LPUART32_UARTMATCH		0x10
#define LPUART32_UARTMODIR		0x14
#define LPUART32_UARTFIFO		0x18
#define LPUART32_UARTWATER		0x1c

#define LPUART32_UARTBAUD_MAEN1		0x80000000
#define LPUART32_UARTBAUD_MAEN2		0x40000000
#define LPUART32_UARTBAUD_M10		0x20000000
#define LPUART32_UARTBAUD_TDMAE		0x00800000
#define LPUART32_UARTBAUD_RDMAE		0x00200000
#define LPUART32_UARTBAUD_MATCFG	0x00400000
#define LPUART32_UARTBAUD_BOTHEDGE	0x00020000
#define LPUART32_UARTBAUD_RESYNCDIS	0x00010000
#define LPUART32_UARTBAUD_LBKDIE	0x00008000
#define LPUART32_UARTBAUD_RXEDGIE	0x00004000
#define LPUART32_UARTBAUD_SBNS		0x00002000
#define LPUART32_UARTBAUD_SBR		0x00000000
#define LPUART32_UARTBAUD_SBR_MASK	0x1fff
#define LPUART32_UARTBAUD_OSR_MASK	0x1f
#define LPUART32_UARTBAUD_OSR_SHIFT	24

#define LPUART32_UARTSTAT_LBKDIF	0x80000000
#define LPUART32_UARTSTAT_RXEDGIF	0x40000000
#define LPUART32_UARTSTAT_MSBF		0x20000000
#define LPUART32_UARTSTAT_RXINV		0x10000000
#define LPUART32_UARTSTAT_RWUID		0x08000000
#define LPUART32_UARTSTAT_BRK13		0x04000000
#define LPUART32_UARTSTAT_LBKDE		0x02000000
#define LPUART32_UARTSTAT_RAF		0x01000000
#define LPUART32_UARTSTAT_TDRE		0x00800000
#define LPUART32_UARTSTAT_TC		0x00400000
#define LPUART32_UARTSTAT_RDRF		0x00200000
#define LPUART32_UARTSTAT_IDLE		0x00100000
#define LPUART32_UARTSTAT_OR		0x00080000
#define LPUART32_UARTSTAT_NF		0x00040000
#define LPUART32_UARTSTAT_FE		0x00020000
#define LPUART32_UARTSTAT_PE		0x00010000
#define LPUART32_UARTSTAT_MA1F		0x00008000
#define LPUART32_UARTSTAT_M21F		0x00004000

#define LPUART32_UARTCTRL_R8T9		0x80000000
#define LPUART32_UARTCTRL_R9T8		0x40000000
#define LPUART32_UARTCTRL_TXDIR		0x20000000
#define LPUART32_UARTCTRL_TXINV		0x10000000
#define LPUART32_UARTCTRL_ORIE		0x08000000
#define LPUART32_UARTCTRL_NEIE		0x04000000
#define LPUART32_UARTCTRL_FEIE		0x02000000
#define LPUART32_UARTCTRL_PEIE		0x01000000
#define LPUART32_UARTCTRL_TIE		0x00800000
#define LPUART32_UARTCTRL_TCIE		0x00400000
#define LPUART32_UARTCTRL_RIE		0x00200000
#define LPUART32_UARTCTRL_ILIE		0x00100000
#define LPUART32_UARTCTRL_TE		0x00080000
#define LPUART32_UARTCTRL_RE		0x00040000
#define LPUART32_UARTCTRL_RWU		0x00020000
#define LPUART32_UARTCTRL_SBK		0x00010000
#define LPUART32_UARTCTRL_MA1IE		0x00008000
#define LPUART32_UARTCTRL_MA2IE		0x00004000
#define LPUART32_UARTCTRL_IDLECFG	GENMASK(10, 8)
#define LPUART32_UARTCTRL_LOOPS		0x00000080
#define LPUART32_UARTCTRL_DOZEEN	0x00000040
#define LPUART32_UARTCTRL_RSRC		0x00000020
#define LPUART32_UARTCTRL_M		0x00000010
#define LPUART32_UARTCTRL_WAKE		0x00000008
#define LPUART32_UARTCTRL_ILT		0x00000004
#define LPUART32_UARTCTRL_PE		0x00000002
#define LPUART32_UARTCTRL_PT		0x00000001

#define LPUART32_UARTDATA_NOISY		0x00008000
#define LPUART32_UARTDATA_PARITYE	0x00004000
#define LPUART32_UARTDATA_FRETSC	0x00002000
#define LPUART32_UARTDATA_RXEMPT	0x00001000
#define LPUART32_UARTDATA_IDLINE	0x00000800
#define LPUART32_UARTDATA_MASK		0x3ff

#define LPUART32_UARTMODIR_IREN		0x00020000
#define LPUART32_UARTMODIR_RTSWATER	GENMASK(10, 8)
#define LPUART32_UARTMODIR_TXCTSSRC	0x00000020
#define LPUART32_UARTMODIR_TXCTSC	0x00000010
#define LPUART32_UARTMODIR_RXRTSE	0x00000008
#define LPUART32_UARTMODIR_TXRTSPOL	0x00000004
#define LPUART32_UARTMODIR_TXRTSE	0x00000002
#define LPUART32_UARTMODIR_TXCTSE	0x00000001

#define LPUART32_UARTFIFO_TXEMPT	0x00800000
#define LPUART32_UARTFIFO_RXEMPT	0x00400000
#define LPUART32_UARTFIFO_TXOF		0x00020000
#define LPUART32_UARTFIFO_RXUF		0x00010000
#define LPUART32_UARTFIFO_TXFLUSH	0x00008000
#define LPUART32_UARTFIFO_RXFLUSH	0x00004000
#define LPUART32_UARTFIFO_RXIDEN	GENMASK(12, 10)
#define LPUART32_UARTFIFO_TXOFE		0x00000200
#define LPUART32_UARTFIFO_RXUFE		0x00000100
#define LPUART32_UARTFIFO_TXFE		0x00000080
#define LPUART32_UARTFIFO_FIFOSIZE_MASK	0x7
#define LPUART32_UARTFIFO_TXSIZE_OFF	4
#define LPUART32_UARTFIFO_RXFE		0x00000008
#define LPUART32_UARTFIFO_RXSIZE_OFF	0
#define LPUART32_UARTFIFO_DEPTH(x)	(0x1 << ((x) ? ((x) + 1) : 0))

#define LPUART32_UARTWATER_COUNT_MASK	0xff
#define LPUART32_UARTWATER_TXCNT_OFF	8
#define LPUART32_UARTWATER_RXCNT_OFF	24
#define LPUART32_UARTWATER_WATER_MASK	0xff
#define LPUART32_UARTWATER_TXWATER_OFF	0
#define LPUART32_UARTWATER_RXWATER_OFF	16

static inline void lpuart32_setbrg(void __iomem *base,
				 unsigned int refclock,
				 unsigned int baudrate)
{
	u32 sbr;

	sbr = (refclock / (16 * baudrate));
	writel(sbr, base + LPUART32_UARTBAUD);
}

static inline void lpuart32_setup(void __iomem *base,
				unsigned int refclock)
{
	lpuart32_setbrg(base, refclock, CONFIG_BAUDRATE);
	writel(LPUART32_UARTCTRL_TE | LPUART32_UARTCTRL_RE, base + LPUART32_UARTCTRL);
}

static inline void lpuart32_putc(void __iomem *base, int c)
{
	while (!(readl(base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_TDRE));

	writel(c, base + LPUART32_UARTDATA);
}

static inline void imx9_uart_setup(void __iomem *uartbase)
{
	/*
	 * On i.MX9 the registers start at offset 0x10
	 */
	BUG_ON((unsigned long)uartbase & 0x10);

	lpuart32_setup(uartbase + 0x10, 24000000);
}

#endif
